package org.atovio.coolexam.common.interceptor;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.atovio.coolexam.annotation.AuthAccess;
import org.atovio.coolexam.entity.User;
import org.atovio.coolexam.exception.AuthenticationException;
import org.atovio.coolexam.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Objects;

/**
 * token 验证的拦截器
 */
public class JWTInterceptor implements HandlerInterceptor {

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

        // 处理被 @AuthAccess 注解标注的方法，放行该方法。以此来配置放行的路径
        if (handler instanceof HandlerMethod) {
            AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);
            if (!Objects.isNull(annotation)){
                return true;
            }
        }

        // 从请求里获得token
        String token = request.getHeader("token");
        if (StrUtil.isBlank(token)) {
            // 如果请求头里没有token，从url参数中查看有没有token
            token = request.getParameter("token");
        }

        // 已经费尽力气找token了, 它到底有没有
        if (StrUtil.isBlank(token)) {
            // 请求里确实是没有token呀！（恼）
            throw new AuthenticationException("用户权限不足，请登录1");
        } else {
            // token存在,解析其中信息
            int userId;
            try {
                // 首先从token中获取userId
                userId = Integer.parseInt(JWT.decode(token).getAudience().get(0));
            } catch (JWTDecodeException e) {
                // token是假的(token不符合标准或是token本身有错误导致解码失败)！！！抛异常
                throw new AuthenticationException("用户权限不足，请登录2");
            }
            // 其次根据userId查询数据库数据，
            User dbUser = userMapper.selectByUserId(userId);
            if (Objects.isNull(dbUser)) {
                // 如果根据userId查不到,即token不正确,抛异常
                throw new AuthenticationException("用户权限不足，请登录3");
            } else {
                // 确实从数据库中查到userId对应的记录了,那么就开始认证啦
                // 对密码加密，生成验证器
                JWTVerifier verifier = JWT.require(Algorithm.HMAC256(dbUser.getPassword())).build();
                try {
                    // 验证token
                    verifier.verify(token);
                } catch (JWTVerificationException e) {
                    throw new AuthenticationException("用户权限不足，请登录4");
                }
                // 终于，token验证通过了
                return true;
            }
        }
    }
}
